package il.technion.cs236369.webserver;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.file.AccessDeniedException;
import java.util.Properties;

import org.apache.http.Header;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicHttpResponse;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpDateGenerator;

public class DefaultlHandler implements TypeHandler 
{
	private Properties properties;

	public DefaultlHandler(Properties prop)
	{
		properties = prop;
	}
	
	public HttpResponse handle(ExtendedHttpRequest request)
	{
		//creating a response with the basic parameters
		HttpResponse response = CreateBaseForResponse();
		if (hasConvertHeader(request))
			response.setHeader(HttpHeaders.CONTENT_TYPE,WebServer.map.getMimeType("json"));
		else
			response.setHeader(HttpHeaders.CONTENT_TYPE,WebServer.map.getContentType(request));
		
		String XHTML = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\""+
				"\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" +
				"<html xmlns=\"http://www.w3.org/1999/xhtml\">\n";
		
		if (request.getType().equals("POST"))
		{
			respondToBadPostRequest(response);
			return response;
		} else
		{
			try
			{
				// handles the case of a GET request with no handler associated
				// catchers handle the different reasons for failing to fetch file 
				if (hasConvertHeader(request))
				{
					String fileContnetXML = getFile(request.getPath());
					XML2JSON parser = new XML2JSON(fileContnetXML);

					StringEntity fileContnet = new StringEntity(XHTML + parser.convert() );
					response.setHeader(HttpHeaders.CONTENT_LENGTH, Long.toString(fileContnet.getContentLength()));
					response.setEntity(fileContnet);
				} else
				{	
					StringEntity fileContnet = null;
					fileContnet = new StringEntity( getFile(request.getPath()) );
					response.setHeader(HttpHeaders.CONTENT_LENGTH, Long.toString(fileContnet.getContentLength()));
					response.setEntity(fileContnet);
				}
				return response;
			}
			catch (AccessDeniedException e ){
				try {
					changeResponseToNotFoundResponse(response,"access denied to file " + request.getPath());
					return response;
				} catch (UnsupportedEncodingException e1) {
					e1.printStackTrace();
				}
			}
			catch (FileNotFoundException e )
			{
				try
				{
					changeResponseToNotFoundResponse(response,"File Not found");
					return response;
				} catch (UnsupportedEncodingException e1)
				{
					e1.printStackTrace();
				}
			}  catch (IOException e)
			{
				try
				{
					changeResponseToNotFoundResponse(response,"Can't read file");
					e.printStackTrace();
					return response;
				} catch (UnsupportedEncodingException e1)
				{
					e1.printStackTrace();
				}
			}
		}
		return response;
	}
	
	private boolean hasConvertHeader(ExtendedHttpRequest request)
	{
		for (Header header: request.getHttpRequest().getAllHeaders())
			if (header.getName().equals("convert") && header.getValue().equals("xml/json"))
				return true;
		return false;
	}

	/**
	 * This mehtod Changes the status of the response to be an error response
	 *  corresponding to 400 error response and attaches a body which reports about the post error  
	 * @param response
	 * @throws UnsupportedEncodingException
	 */
	private void respondToBadPostRequest(HttpResponse response) {
		String XHTML = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\""+
				"\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" +
				"<html xmlns=\"http://www.w3.org/1999/xhtml\">\n";
		response.setStatusCode(400);
		response.setReasonPhrase("Bad Request");
		response.setHeader(HttpHeaders.CONTENT_TYPE,"text/html");
		String errorPage = "<html>" + "<head><title> Error 400: </title></head><body><center><h1><font color=\"red\"> <p>"
				+ "Post handled by handlers only </p><p>  Post handled by handlers only </p></font></h1></center></body></html>";
		StringEntity error = null;
		try {
			error = new StringEntity(XHTML+errorPage);
			response.setHeader(HttpHeaders.CONTENT_LENGTH, Long.toString(error.getContentLength()));
			response.setHeader(HttpHeaders.CONTENT_TYPE, "text/html");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		response.setEntity(error);
		
	}

	/**
	 * This mehtod Changes the status of the response to be an error response
	 *  corresponding to 404 error response and attaches a body which reports about the error  
	 * @param response
	 * @throws UnsupportedEncodingException
	 */
	private void changeResponseToNotFoundResponse(HttpResponse response,String message) throws UnsupportedEncodingException {
		String XHTML = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\""+
				"\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" +
				"<html xmlns=\"http://www.w3.org/1999/xhtml\">\n";
		response.setStatusCode(404);
		response.setReasonPhrase("Not Found");
		response.setHeader(HttpHeaders.CONTENT_TYPE,"text/html");
		String errorPage = XHTML+"<html>" + "<head><title> Error 404: </title></head><body><center><h1><font color=\"red\"> <p>"
				+ "Error  404:  Not Found </p><p>" + message + " </p></font></h1></center></body></html>";
		StringEntity error = new StringEntity(errorPage);
		response.setHeader(HttpHeaders.CONTENT_LENGTH, Long.toString(error.getContentLength()));
		response.setHeader(HttpHeaders.CONTENT_TYPE, "text/html");
		response.setEntity(error);
		}
	
	/**
	 * Tries to fetch a file and simply write it into a string
	 * If path points to a directory returns a html page which reports the content of the directory
	 * If fails throws an exception
	 * @param path
	 * @return
	 * @throws IOException 
	 */
	private String getFile(String path) throws FileNotFoundException, AccessDeniedException, IOException
	{
		String XHTML = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\""+
				"\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" +
				"<html xmlns=\"http://www.w3.org/1999/xhtml\">\n";
		
		File file = new File(path);
		if ( file.isDirectory() ){
			StringBuilder fileContent = new StringBuilder();
			String ls = System.getProperty("line.separator");
			fileContent.append(XHTML);
			fileContent.append("<html><head><title>Folder content</title></head><body> <p>The direcotry contains the following files and directories, please relate to a file </p>");
			fileContent.append( ls );
			for (String fileName: file.list()){
				fileContent.append("<p>");
				fileContent.append( fileName );
				fileContent.append( ls );
				fileContent.append("</p>");
			}
			fileContent.append("</body></html>");
			return fileContent.toString();
			}
		if (!file.exists() && !file.isDirectory() ){
			throw new FileNotFoundException();
		}
		BufferedReader reader = new BufferedReader( new FileReader (file));
		String line  = null;
		StringBuilder fileContent = new StringBuilder();
		String ls = System.getProperty("line.separator");
		while( ( line = reader.readLine() ) != null ) {
		   fileContent.append( line );
		   fileContent.append( ls );
		}
		return fileContent.toString();
	}
	
	/**
	 * creates a response with the basic fields (date, status line, connection header)
	 * @return
	 */
	private HttpResponse CreateBaseForResponse() 
	{
//		Creating the request according to the requirement, for example:
//		HTTP/1.1 200 OK
//		Date: Sun, 02 Mar 2008 04:37:22 GMT
//		Content-Length: 3545
//		Connection: close
//		Content-Type: image/gif
		HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK");
		response.setHeader(HttpHeaders.DATE, new HttpDateGenerator().getCurrentDate());
		response.setHeader(HttpHeaders.CONNECTION, HTTP.CONN_CLOSE);
		return response;
	}
	
}
